﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Web.Routing;
using System.Web.Mvc;
using System.Web.Compilation;
using System.Configuration;
using System.IO;
using System.Web;

namespace Kaleido.Util.Mvc
{
    public static class UtilConfig
    {
        //<add key="StaticViewLocation" value="/Static"/>
        public static string StaticViewLocation
        {
            get
            {
                var path = ConfigurationManager.AppSettings["StaticViewLocation"];
                if (Directory.Exists(HttpContext.Current.Server.MapPath(("~/" + path).Replace("//", "/"))))
                {
                    return ("/" + path).Replace("//", "/");
                }
                return "/";
            }
        }
        
        //<add key="StaticExtensions" value="html|css|js"/>
        public static string[] StaticExtensions
        {
            get
            {
                var extl=ConfigurationManager.AppSettings["StaticExtensions"];
                if (extl != null)
                {
                    var extensions = extl.Split('|');
                    if (extensions.Length > 0)
                        return extensions.Select(e => e.Trim().ToLower()).ToArray();
                }
                return null;
            }
        }

        public static void RegisterRoutes(RouteCollection routes)
        {
            routes.MapRoute(
                "Static",
                "{*req}",
                new { controller = "Static", action = "Index" },
                new { req = @".+\.(" + string.Join("|", StaticExtensions) + @")($|[?].*)" },
                new string[] { "Kaleido.Util.Mvc.Controllers" }
                );

            ViewEngines.Engines.Add(new StaticRazorViewEngine());
        }
    }

    public class StaticRazorViewEngine : RazorViewEngine
    {
        public override ViewEngineResult FindView(ControllerContext controllerContext, string viewName, string masterName, bool useCache)
        {
            if (controllerContext == null)
            {
                throw new ArgumentNullException("controllerContext");
            }
            if (string.IsNullOrEmpty(viewName))
            {
                throw new ArgumentException("Common_NullOrEmpty", "viewName");
            }
            string requiredString = controllerContext.RouteData.GetRequiredString("controller");

            IEnumerable<string> searchedLocations, l;
            viewName = (UtilConfig.StaticViewLocation + viewName).Replace("//", "/");
            var viewPath = Process(viewName, out l);
            searchedLocations = l;;
            masterName = (UtilConfig.StaticViewLocation + masterName).Replace("//", "/");
            var masterPath = Process(masterName, out l);

            searchedLocations = searchedLocations.Union(l);

            if (string.IsNullOrEmpty(viewPath) | (string.IsNullOrEmpty(viewPath) & !string.IsNullOrEmpty(masterName)))
            {
                return new ViewEngineResult(searchedLocations);
            }
            else
            {
                return new ViewEngineResult(this.CreateView(controllerContext, viewPath, masterPath), this);
            }
        }

        public override ViewEngineResult FindPartialView(ControllerContext controllerContext, string partialViewName, bool useCache)
        {
            if (controllerContext == null)
            {
                throw new ArgumentNullException("controllerContext");
            }
            if (string.IsNullOrEmpty(partialViewName))
            {
                throw new ArgumentException("Common_NullOrEmpty", "viewName");
            }
            string requiredString = controllerContext.RouteData.GetRequiredString("controller");

            IEnumerable<string> searchedLocations;
            partialViewName = (UtilConfig.StaticViewLocation + partialViewName).Replace("//", "/");
            string path = Process(partialViewName, out searchedLocations);


            if (string.IsNullOrEmpty(path))
            {
                return new ViewEngineResult(searchedLocations);
            }
            else
            {
                return new ViewEngineResult(this.CreatePartialView(controllerContext, path), this);
            }
        }

        public string Process(string reqPath, out IEnumerable<string> searchedLocations)
        {
            searchedLocations = new LinkedList<string>();
            foreach (var ext in UtilConfig.StaticExtensions)
            {
                var end = "." + ext;
                if (reqPath.EndsWith(end))
                {
                    var path = reqPath.Substring(0, reqPath.Length - end.Length);
                    foreach (var fe in FileExtensions)
                    {
                        var vpath = path + "." + fe;
                        ((LinkedList<string>)searchedLocations).AddLast(vpath);
                        if (File.Exists(HttpContext.Current.Server.MapPath(("~/" + vpath).Replace("//", "/"))))
                            if (BuildManager.GetCompiledType(vpath) != null)
                                return vpath;
                    }
                }
            }
            return null;
        }
    }
}
